<template>
    <div class="upload-img">
        <el-form-item label="" label-width="0px" :prop="prop" :required="required">
            <div class="uploader-wrap">
                <div class="uploader-tit">
                    <div v-show="maxCount != 9999">
                        <span class="red-star" v-if="required">*</span>
                        {{ label }}
                        {{ modelValue.length }}<span>/</span>{{ maxCount }}
                    </div>
                    <div class="count-info" v-if="!readonly">
                        <el-upload class="upload-btn" v-if="modelValue.length < maxCount * 1" action="" :show-file-list="false" :http-request="httpRequest" :before-upload="beforeUpload"> <span class="el-icon-plus upload-img-icon"></span>上传 </el-upload>
                    </div>
                </div>
                <div class="upload-box">
                    <div class="custom-file-list">
                        <!-- 文件列表 -->
                        <div class="custom-file-item" v-for="(fitem, index) in modelValue" :key="`file_${index}`">
                            <div class="file-info">
                                <div class="file-image">
                                    <template v-if="fitem.fileType.indexOf('image') > -1">
                                        <img width="50" height="50" :radius="4" :src="fitem.fileUrl" />
                                    </template>
                                    <div class="file-type" v-else-if="fitem.fileType === 'application/pdf'">
                                        <img width="50" height="50" :radius="4" src="@/assets/svgs/file_pdf.svg" />
                                    </div>
                                    <div class="file-type" v-else-if="fitem.fileType === 'application/msword'">
                                        <img width="50" height="50" :radius="4" src="@/assets/svgs/file_word.svg" />
                                    </div>
                                    <div class="file-type" v-else-if="/\.(doc|docx)$/.test(fitem.fileName)">
                                        <img width="50" height="50" :radius="4" src="@/assets/svgs/file_word.svg" />
                                    </div>
                                    <div class="file-type" v-else-if="fitem.fileType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'">
                                        <img width="50" height="50" :radius="4" src="@/assets/svgs/file_excel.svg" />
                                    </div>
                                </div>
                                <div class="file-tit">
                                    <div class="file-name">{{ fitem.fileName }}</div>
                                    <div class="file-op" v-if="fitem.fileSize">
                                        <span class="file-size">{{ fileSizeFn(fitem.fileSize) }}</span>
                                        <div class="file-btns"><span @click="preview(fitem, index)">预览</span><span @click="download(fitem)">下载</span><span v-if="!readonly" @click="deleteFile(fitem, index)">删除</span></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div v-if="!readonly" class="tip">
                    注：{{ mimeTypeTip.replace('只', '') }}<span v-if="maxSize > 0">，小于{{ maxSize }}M</span><span v-show="maxCount != 9999">，最多{{ maxCount }}个</span>。
                </div>
            </div>
        </el-form-item>
        <big-img :bigImgShow="bigImgObj.bigImgShow" :bigImgData="imgs" :selectIndex="bigImgObj.initialIndex" @changeBigImgShow="changeBigImgShow" />
    </div>
</template>

<script setup name="uploadFile">
import { defineProps, computed, defineEmits, ref } from 'vue'
import { upload } from '@/api/common'
import { ElMessageBox } from 'element-plus'
import bigImg from './bigImg.vue'

const props = defineProps({
    modelValue: { type: [Array, String], default: () => [] },
    prop: { type: String, default: '' },
    label: { type: String, default: '上传文件' },
    required: { type: Boolean, default: false },
    readonly: { type: Boolean, default: false }, // 该属性控制是否可以上传和删除文件，如果为true，则不显示上传和删除按钮
    maxCount: { type: [String, Number], default: 10 },
    // 文件最大容量，为0则不限制
    maxSize: { type: Number, default: 0 },
    mimeType: {
        type: Array,
        default: () => {
            return ['xlsx', 'doc', 'image/png', 'image/jpeg', 'image/gif', 'application/pdf', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel']
        }
    },
    mimeTypeTip: {
        type: String,
        default: '附件只支持图片/PDF/word/excel'
    }
})
const emit = defineEmits(['update:modelValue', 'fileChange'])

const bigImgObj = ref({
    initialIndex: 1,
    bigImgShow: false,
    bigImgData: []
})
// 过滤出图片
const imgs = computed(() => {
    let imgs = []
    if (props.modelValue && props.modelValue.length > 0) {
        const filters = props.modelValue.filter((item) => item.fileType.indexOf('image') > -1)
        imgs = filters.map((x) => x.fileUrl)
    }
    return imgs
})

// 上传文件之前校验文件类型及大小是否符合要求
const beforeUpload = (file) => {
    if (props.maxSize === 0) {
        // 如果不限制文件大小，则判断文件类型是否符合要求
        if (props.mimeType.indexOf(file.type) > -1) {
            return true
        } else {
            ElMessage.error(`${props.mimeTypeTip}`)
            return false
        }
    }
    if (props.mimeType.indexOf(file.type) > -1 && file.size <= props.maxSize * 1024 * 1024) {
        return true
    }
    ElMessage.error(`${props.mimeTypeTip}，小于${props.maxSize}M`)
    return false
}
const fileSizeFn = (fileSize) => {
    fileSize = +fileSize
    return fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(2)}KB` : `${(fileSize / 1024 / 1024).toFixed(2)}MB`
}

// 上传文件的动作
const httpRequest = (item) => {
    let { name: fileName, size: fileSize, type: fileType } = item.file
    const token = new Date().getTime()
    const fileItem = {
        fileType,
        fileName,
        fileSize,
        uploadPercent: 0,
        fileUrl: '',
        token
    }
    let formData = new FormData()
    formData.append('file', item.file)
    upload(formData).then((res = {}) => {
        if (res.code === 200) {
            fileItem.fileUrl = res.data.fileUrls[0]
            fileItem.uploadPercent = 100
            let newData = [...props.modelValue, fileItem]
            emit('update:modelValue', newData)
            emit('fileChange', newData, true) // 第三参数 为了识别新增、删除的操作
        }
    })
}

const deleteFile = (fitem, index) => {
    // 添加再次确认提示
    ElMessageBox.confirm('确定删除？', `提示`, {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    })
        .then(async () => {
            const temp = [...props.modelValue]
            temp.splice(index, 1)
            emit('update:modelValue', temp)
            emit('fileChange', temp, true) // 第三参数 为了识别新增、删除的操作
            emit('delFile', fitem) // 监听删除
        })
        .catch(() => {})
}

// 预览图片
const preview = (fitem) => {
    // 点击文件操作，如果是图片则预览
    if (fitem.fileType.indexOf('image') > -1) {
        let index = imgs.value.findIndex((x) => x === fitem.fileUrl)
        previewImg(index)
    } else {
        download(fitem)
    }
}
// 预览图片
function previewImg(index) {
    bigImgObj.value.initialIndex = index
    bigImgObj.value.bigImgShow = true
}
// 关闭查看大图
function changeBigImgShow() {
    bigImgObj.value.bigImgShow = false
}
const download = (fitem) => {
    const downUrl = fitem.fileUrl
    const eleLink = document.createElement('a')
    eleLink.download = fitem.fileName
    eleLink.style.display = 'none'
    // 字符内容转变成blob地址
    eleLink.href = downUrl
    eleLink.target = '_blank'
    // 触发点击
    document.body.appendChild(eleLink)
    eleLink.click()
    // 然后移除
    document.body.removeChild(eleLink)
}
</script>

<style lang="scss" scoped>
.uploader-wrap {
    width: 100%;
    .uploader-tit {
        display: flex;
        justify-content: space-between;
        padding: 0px;
        .upload-btn {
            color: #027aff;
        }
    }
}
.upload-box {
    .custom-file-list {
        .custom-file-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            .file-info {
                display: flex;
                overflow: hidden;
                .file-type {
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    width: 50px;
                    height: 50px;
                }
                .file-tit {
                    flex: 1;
                    overflow: hidden;
                    padding: 4px 0 0 10px;
                    color: rgba(0, 0, 0, 0.65);
                    line-height: 22px;
                    .file-name {
                        overflow: hidden;
                        white-space: nowrap;
                        text-overflow: ellipsis;
                    }
                    .file-op {
                        color: #999;
                        margin: 16px 0 0;
                        display: flex;
                        align-items: center;
                        .file-btns {
                            margin-left: 20px;
                            > span {
                                color: var(--primary-color);
                                cursor: pointer;
                                margin-right: 20px;
                                &:last-child {
                                    margin-right: 0;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
.tips {
    font-size: 14px;
}
</style>
